# -*- coding: utf-8 -*-
# @Author	: brotherbaby
# @Date		: 2023/11/1 13:54
# @Last Modified by:   brotherbaby
# @Last Modified time: 2023/11/1 13:54
# Thanks for your comments!

import json
import logging
import traceback

from flask import request
from sqlalchemy import func

from src.consts import ClientType
from src.db_proxy.connect import DbConnector
from src.db_proxy.models.permission import Permission
from src.db_proxy.models.role import Role
from src.db_proxy.models.role_assignment import RoleAssignment
from src.db_proxy.models.user_assignment import UserAssignment
from src.tornadoweb_app import app
from .utils import verify_token

logger = logging.getLogger(__name__)


@app.route("/wechat_milangze/query_assignment", methods=["GET"])
def query_assignment_api():
    resp = {"code": 0, "message": "success"}
    try:
        params = request.args
        for f in ["access_token"]:
            if not params.get(f):
                resp.update({"code": -1, "message": "lack %s" % f})
                return json.dumps(resp)
        if not verify_token(params.get("access_token"), ClientType.UserAdmin.value):
            resp.update({"code": 403, "message": "invalid access_token, query new one and try again"})
            return json.dumps(resp)
        db_conn = DbConnector()
        session = db_conn.get_session()
        q = [Permission.obsoleted == False]
        if params.get("name"):
            q.append([Permission.name.ilike(f"%{params['name']}%")])
        offset = int(params.get("page_size", 10)) * (int(params.get("page", 1)) - 1)
        pers_count = session.query(func.count(Permission.id)).filter(*q).scalar()
        pers = session.query(Permission).filter(*q).offset(offset).limit(
            int(params.get("page_size", 10))).all()
        resp["data"] = {"total": pers_count, "records": [per.get_fields() for per in pers]}
        db_conn.close_session(session)
    except Exception as e:
        logger.error(traceback.format_exc())
        resp.update({"code": -1, "message": str(e)})
    return json.dumps(resp)


@app.route("/wechat_milangze/add_assignment", methods=["POST"])
def add_assignment_api():
    resp = {"code": 0, "message": "success"}
    try:
        params = request.get_json()
        for f in ["access_token"]:
            if not params.get(f):
                resp.update({"code": -1, "message": "lack %s" % f})
                return json.dumps(resp)
        if not verify_token(params.get("access_token"), ClientType.UserAdmin.value):
            resp.update({"code": 403, "message": "invalid access_token, query new one and try again"})
            return json.dumps(resp)
        db_conn = DbConnector()
        session = db_conn.get_session()
        session.add(Permission(**params))
        session.commit()
        db_conn.close_session(session)
    except Exception as e:
        logger.error(traceback.format_exc())
        resp.update({"code": -1, "message": str(e)})
    return json.dumps(resp)


@app.route("/wechat_milangze/update_assignment", methods=["POST"])
def update_assignment_api():
    resp = {"code": 0, "message": "success"}
    try:
        params = request.get_json()
        for f in ["id", "access_token"]:
            if not params.get(f):
                resp.update({"code": -1, "message": "lack %s" % f})
                return json.dumps(resp)
        if not verify_token(params.get("access_token"), ClientType.UserAdmin.value):
            resp.update({"code": 403, "message": "invalid access_token, query new one and try again"})
            return json.dumps(resp)
        db_conn = DbConnector()
        session = db_conn.get_session()
        session.query(Permission).filter(Permission.id == params["id"], Permission.obsoleted == False).update(**params)
        session.commit()
        db_conn.close_session(session)
    except Exception as e:
        logger.error(traceback.format_exc())
        resp.update({"code": -1, "message": str(e)})
    return json.dumps(resp)


@app.route("/wechat_milangze/delete_assignment", methods=["POST"])
def delete_assignment_api():
    resp = {"code": 0, "message": "success"}
    try:
        params = request.get_json()
        for f in ["id", "access_token"]:
            if not params.get(f):
                resp.update({"code": -1, "message": "lack %s" % f})
                return json.dumps(resp)
        if not verify_token(params.get("access_token"), ClientType.UserAdmin.value):
            resp.update({"code": 403, "message": "invalid access_token, query new one and try again"})
            return json.dumps(resp)
        db_conn = DbConnector()
        session = db_conn.get_session()
        session.query(Permission).filter(Permission.id == params["id"]).delete()
        session.commit()
        db_conn.close_session(session)
    except Exception as e:
        logger.error(traceback.format_exc())
        resp.update({"code": -1, "message": str(e)})
    return json.dumps(resp)


@app.route("/wechat_milangze/query_role", methods=["GET"])
def query_role_api():
    resp = {"code": 0, "message": "success"}
    try:
        params = request.args
        for f in ["access_token"]:
            if not params.get(f):
                resp.update({"code": -1, "message": "lack %s" % f})
                return json.dumps(resp)
        if not verify_token(params.get("access_token"), ClientType.UserAdmin.value):
            resp.update({"code": 403, "message": "invalid access_token, query new one and try again"})
            return json.dumps(resp)
        db_conn = DbConnector()
        session = db_conn.get_session()
        q = [Role.obsoleted == False]
        if params.get("name"):
            q.append([Role.name.ilike(f"%{params['name']}%")])
        offset = int(params.get("page_size", 10)) * (int(params.get("page", 1)) - 1)
        roles_count = session.query(func.count(Role.id)).filter(*q).scalar()
        roles = session.query(Role).filter(*q).offset(offset).limit(
            int(params.get("page_size", 10))).all()
        resp["data"] = {"total": roles_count, "records": [ro.get_fields() for ro in roles]}
        db_conn.close_session(session)
    except Exception as e:
        logger.error(traceback.format_exc())
        resp.update({"code": -1, "message": str(e)})
    return json.dumps(resp)


@app.route("/wechat_milangze/add_role", methods=["POST"])
def add_role_api():
    resp = {"code": 0, "message": "success"}
    try:
        params = request.get_json()
        for f in ["access_token"]:
            if not params.get(f):
                resp.update({"code": -1, "message": "lack %s" % f})
                return json.dumps(resp)
        if not verify_token(params.get("access_token"), ClientType.UserAdmin.value):
            resp.update({"code": 403, "message": "invalid access_token, query new one and try again"})
            return json.dumps(resp)
        db_conn = DbConnector()
        session = db_conn.get_session()
        session.add(Role(**params))
        session.commit()
        db_conn.close_session(session)
    except Exception as e:
        logger.error(traceback.format_exc())
        resp.update({"code": -1, "message": str(e)})
    return json.dumps(resp)


@app.route("/wechat_milangze/update_role", methods=["POST"])
def update_role_api():
    resp = {"code": 0, "message": "success"}
    try:
        params = request.get_json()
        for f in ["id", "access_token"]:
            if not params.get(f):
                resp.update({"code": -1, "message": "lack %s" % f})
                return json.dumps(resp)
        if not verify_token(params.get("access_token"), ClientType.UserAdmin.value):
            resp.update({"code": 403, "message": "invalid access_token, query new one and try again"})
            return json.dumps(resp)
        db_conn = DbConnector()
        session = db_conn.get_session()
        session.query(Role).filter(Role.id == params["id"], Role.obsoleted == False).update(**params)
        session.commit()
        db_conn.close_session(session)
    except Exception as e:
        logger.error(traceback.format_exc())
        resp.update({"code": -1, "message": str(e)})
    return json.dumps(resp)


@app.route("/wechat_milangze/delete_role", methods=["POST"])
def delete_role_api():
    resp = {"code": 0, "message": "success"}
    try:
        params = request.get_json()
        for f in ["id", "access_token"]:
            if not params.get(f):
                resp.update({"code": -1, "message": "lack %s" % f})
                return json.dumps(resp)
        if not verify_token(params.get("access_token"), ClientType.UserAdmin.value):
            resp.update({"code": 403, "message": "invalid access_token, query new one and try again"})
            return json.dumps(resp)
        db_conn = DbConnector()
        session = db_conn.get_session()
        session.query(Role).filter(Role.id == params["id"]).delete()
        session.commit()
        db_conn.close_session(session)
    except Exception as e:
        logger.error(traceback.format_exc())
        resp.update({"code": -1, "message": str(e)})
    return json.dumps(resp)


@app.route("/wechat_milangze/add_permission2role", methods=["POST"])
def add_permission2role_api():
    resp = {"code": 0, "message": "success"}
    try:
        params = request.get_json()
        for f in ["role_id", "permission_id", "access_token"]:
            if not params.get(f):
                resp.update({"code": -1, "message": "lack %s" % f})
                return json.dumps(resp)
        if not verify_token(params.get("access_token"), ClientType.UserAdmin.value):
            resp.update({"code": 403, "message": "invalid access_token, query new one and try again"})
            return json.dumps(resp)
        db_conn = DbConnector()
        session = db_conn.get_session()
        session.add(RoleAssignment(**params))
        session.commit()
        db_conn.close_session(session)
    except Exception as e:
        logger.error(traceback.format_exc())
        resp.update({"code": -1, "message": str(e)})
    return json.dumps(resp)


@app.route("/wechat_milangze/delete_permission2role", methods=["POST"])
def delete_permission2role_api():
    resp = {"code": 0, "message": "success"}
    try:
        params = request.get_json()
        for f in ["id", "access_token"]:
            if not params.get(f):
                resp.update({"code": -1, "message": "lack %s" % f})
                return json.dumps(resp)
        if not verify_token(params.get("access_token"), ClientType.UserAdmin.value):
            resp.update({"code": 403, "message": "invalid access_token, query new one and try again"})
            return json.dumps(resp)
        db_conn = DbConnector()
        session = db_conn.get_session()
        session.query(RoleAssignment).filter(RoleAssignment.id == params.get("id")).delete()
        session.commit()
        db_conn.close_session(session)
    except Exception as e:
        logger.error(traceback.format_exc())
        resp.update({"code": -1, "message": str(e)})
    return json.dumps(resp)


@app.route("/wechat_milangze/add_role2user", methods=["POST"])
def add_role2user_api():
    resp = {"code": 0, "message": "success"}
    try:
        params = request.get_json()
        for f in ["role_id", "user_id", "access_token"]:
            if not params.get(f):
                resp.update({"code": -1, "message": "lack %s" % f})
                return json.dumps(resp)
        if not verify_token(params.get("access_token"), ClientType.UserAdmin.value):
            resp.update({"code": 403, "message": "invalid access_token, query new one and try again"})
            return json.dumps(resp)
        db_conn = DbConnector()
        session = db_conn.get_session()
        session.add(UserAssignment(**params))
        session.commit()
        db_conn.close_session(session)
    except Exception as e:
        logger.error(traceback.format_exc())
        resp.update({"code": -1, "message": str(e)})
    return json.dumps(resp)


@app.route("/wechat_milangze/delete_role2user", methods=["POST"])
def delete_role2user_api():
    resp = {"code": 0, "message": "success"}
    try:
        params = request.get_json()
        for f in ["id", "access_token"]:
            if not params.get(f):
                resp.update({"code": -1, "message": "lack %s" % f})
                return json.dumps(resp)
        if not verify_token(params.get("access_token"), ClientType.UserAdmin.value):
            resp.update({"code": 403, "message": "invalid access_token, query new one and try again"})
            return json.dumps(resp)
        db_conn = DbConnector()
        session = db_conn.get_session()
        session.query(UserAssignment).filter(UserAssignment.id == params.get("id")).delete()
        session.commit()
        db_conn.close_session(session)
    except Exception as e:
        logger.error(traceback.format_exc())
        resp.update({"code": -1, "message": str(e)})
    return json.dumps(resp)


@app.route("/wechat_milangze/query_user_roles", methods=["GET"])
def query_user_roles_api():
    """
    查询用户的角色列表
    :return:
    """
    resp = {"code": 0, "message": "success"}
    try:
        params = request.args
        for f in ["user_id", "access_token"]:
            if not params.get(f):
                resp.update({"code": -1, "message": "lack %s" % f})
                return json.dumps(resp)
        if not verify_token(params.get("access_token"), ClientType.UserAdmin.value):
            resp.update({"code": 403, "message": "invalid access_token, query new one and try again"})
            return json.dumps(resp)
        db_conn = DbConnector()
        session = db_conn.get_session()
        q = [UserAssignment.obsoleted == False, UserAssignment.user_id == int(params["user_id"])]
        offset = int(params.get("page_size", 10)) * (int(params.get("page", 1)) - 1)
        uas_count = session.query(func.count(UserAssignment.id)).filter(*q).scalar()
        uas = session.query(UserAssignment, Role).filter(*q).join(Role).offset(offset).limit(
            int(params.get("page_size", 10))).all()
        res_data = []
        for ua in uas:
            _, role = ua
            res_data.append(role.get_fields())
        resp["data"] = {"total": uas_count, "records": res_data}
        db_conn.close_session(session)
    except Exception as e:
        logger.error(traceback.format_exc())
        resp.update({"code": -1, "message": str(e)})
    return json.dumps(resp)


@app.route("/wechat_milangze/query_role_permissions", methods=["GET"])
def query_role_permissions_api():
    """
    查询角色的权限列表
    :return:
    """
    resp = {"code": 0, "message": "success"}
    try:
        params = request.args
        for f in ["role_id", "access_token"]:
            if not params.get(f):
                resp.update({"code": -1, "message": "lack %s" % f})
                return json.dumps(resp)
        if not verify_token(params.get("access_token"), ClientType.UserAdmin.value):
            resp.update({"code": 403, "message": "invalid access_token, query new one and try again"})
            return json.dumps(resp)
        db_conn = DbConnector()
        session = db_conn.get_session()
        if not isinstance(params.get("role_id"), list):
            params["role_id"] = [params.get("role_id")]
        q = [RoleAssignment.obsoleted == False, RoleAssignment.role_id.in_([int(i) for i in params["role_id"]])]
        offset = int(params.get("page_size", 10)) * (int(params.get("page", 1)) - 1)
        ras_count = session.query(func.count(RoleAssignment.id)).filter(*q).scalar()
        ras = session.query(RoleAssignment, Permission).filter(*q).join(Permission).offset(offset).limit(
            int(params.get("page_size", 10))).all()
        res_data = []
        for ra in ras:
            _, perm = ra
            res_data.append(perm.get_fields())
        resp["data"] = {"total": ras_count, "records": res_data}
        db_conn.close_session(session)
    except Exception as e:
        logger.error(traceback.format_exc())
        resp.update({"code": -1, "message": str(e)})
    return json.dumps(resp)
